﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace GDI_AnalysisComponents
{
    [Serializable()]  
    public class GLine
    {
        private Pen pen;
        private PointF startPt;
        private PointF endPt;
        private Module m = new Module();

        public GLine(PointF startPt, PointF endPt)
        {
            this.pen = new Pen(Color.Blue);
            this.startPt = startPt;
            this.endPt = endPt;          
        }

        public Pen Pen
        {
            get { return pen; }
            set { pen = value; }
        }

        public PointF StartPt
        {
            get { return startPt; }
            set { startPt = value; }
        }

        public PointF EndPt
        {
            get { return endPt; }
            set { endPt = value; }
        }

   
        //画线
        public void DrawGLine(Graphics g)
        {
            g.DrawLine(pen, startPt, endPt);
        }

        //绘直线段
        public void Draw(Graphics g )
        {
            long aPen, oldP;

            //获得当前绘图环境的句柄
            IntPtr hdc = g.GetHdc();
            Win32API.SetROP2(hdc, 10);
            //创建画笔
            aPen = Win32API.CreatePen(0, 1, 16711680);
            //把画笔选入绘图环境，并返回原来的画笔
            oldP = Win32API.SelectObject(hdc, aPen);
            Win32API.LPPOINT prePos = new Win32API.LPPOINT();
            //把画笔移动到直线段的起点处
            Win32API.MoveToEx(hdc, (int)(startPt.X), (int)(startPt.Y), prePos);
            //绘直线段到终点
            Win32API.LineTo(hdc, (int)(endPt.X), (int)(endPt.Y));
            //把原来的画笔选入绘图环境
            Win32API.SelectObject(hdc, oldP);
            //删除新创建的画笔
            Win32API.DeleteObject(aPen);
            //释放绘图环境句柄
            g.ReleaseHdc(hdc);
        }

        //计算包围矩形
         public GBox GetBox()
        {
            GBox aBox = new GBox();
            if (startPt.X == endPt.X)
            {
                aBox.minX = startPt.X - Const.PickRadius;
                aBox.minY = Math.Min(startPt.Y, endPt.Y);
                aBox.maxX = startPt.X + Const.PickRadius;
                aBox.maxY = Math.Max(startPt.Y, endPt.Y);
            }
            else if (startPt.Y == endPt.Y)
            {
                aBox.minX = Math.Min(startPt.X, endPt.X);
                aBox.minY = startPt.Y - Const.PickRadius;
                aBox.maxX = Math.Max(startPt.X, endPt.X);
                aBox.maxY = startPt.Y + Const.PickRadius;
            }
            else
            {
                aBox.minX = Math.Min(startPt.X, endPt.X);
                aBox.minY = Math.Min(startPt.Y, endPt.Y);
                aBox.maxX = Math.Max(startPt.X, endPt.X);
                aBox.maxY = Math.Max(startPt.Y, endPt.Y);
            }

            return aBox;
        }


        //计算点到直线段的距离
        private float distPtoL(PointF pt, GLine gl)
        {
            float px, py, dist;
            float distX, distY;
            float[] kc;

            px = pt.X;
            py = pt.Y;

            //获取直线段的截距式方程，返回斜率和截距
            kc = gl.LineKX();
            //如果为水平直线段
            if (kc[0] == 0)
            {
                distX = 10000;
                distY = Math.Abs(py - gl.StartPt.Y);
            }
            //如果为竖直直线段
            else if (kc[0] == 10000)
            {
                distX = Math.Abs(px - gl.StartPt.X);
                distY = 10000;
            }
            //如果为斜线
            else
            {
                distX = Math.Abs(px - (py - kc[1]) / kc[0]);
                distY = Math.Abs(py - (kc[0] * px + kc[1]));
            }
            //返回水平距离和竖直距离之间的小值
            dist = Math.Min(distX, distY);
            return dist;
        }


        //计算直线段的截距式方程
        private float[] LineKX()
        {
            float kc0, kc1;
            //若直线段不为竖直线段
            if (startPt.X != endPt.X)
            {
                kc0 = (endPt.Y - startPt.Y) / (endPt.X - startPt.X);
            }
            //如果是竖直线段
            else
            {
                kc0 = 10000f;
            }
            //计算截距
            kc1 = startPt.Y - kc0 * startPt.X;
            float[] kc = { kc0, kc1 };

            return kc;
        }


        //拾取直线段
        public bool Pick(PointF pt)
        {
            GBox geBox = new GBox();

            //判断拾取点是否在测试包围矩形中，若不是，
            //则直线段不被拾取
            if (!(m.InBox(GetBox(), pt)))
            {
                return false;
            }
            else
            {
                if (distPtoL(pt, this) < Const.PickRadius)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        //判断拾取点是否位于包围矩形中
        private bool InBox(GBox aBox, PointF pt)
        {
            if (pt.X > aBox.minX && pt.Y > aBox.minY
               && pt.X < aBox.maxX && pt.Y < aBox.maxY)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}
